//  Binary.java
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//       Juan J. Durillo <durillo@lcc.uma.es>
// 
//  Copyright (c) 2011 Antonio J. Nebro, Juan J. Durillo
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package etmo.encodings.variable;

import etmo.core.Variable;
import etmo.util.PseudoRandom;

import java.util.BitSet;

/**
 * This class implements a generic binary string encodings.variable.It can be
 * used as a base class other binary string based classes (e.g., binary coded
 * integer or real variables).
 */
public class Binary extends Variable {

	/**
	 * Stores the bits constituting the binary string. It is implemented using a
	 * BitSet object
	 */
	public BitSet bits_;

	/**
	 * Store the length of the binary string
	 */
	protected int numberOfBits_;

	/**
	 * Default constructor.
	 */
	public Binary() {
	} // Binary

	/**
	 * Constructor
	 * 
	 * @param numberOfBits
	 *            Length of the bit string
	 */
	public Binary(int numberOfBits) {
		numberOfBits_ = numberOfBits;

		bits_ = new BitSet(numberOfBits_);
		for (int i = 0; i < numberOfBits_; i++) {
			if (PseudoRandom.randDouble() < 0.5) {
				bits_.set(i, true);
			} else {
				bits_.set(i, false);
			}
		}
	} // Binary

	/**
	 * Copy constructor.
	 * 
	 * @param variable
	 *            The Binary encodings.variable to copy.
	 */
	public Binary(Binary variable) {
		numberOfBits_ = variable.numberOfBits_;

		bits_ = new BitSet(numberOfBits_);
		for (int i = 0; i < numberOfBits_; i++) {
			bits_.set(i, variable.bits_.get(i));
		}
	} // Binary

	/**
	 * This method is intended to be used in subclass of <code>Binary</code>,
	 * for examples the classes, <code>BinaryReal</code> and <code>BinaryInt
	 * <codes>. In this classes, the method allows to decode the value enconded
	 * in the binary string. As generic variables do not encode any value, this
	 * method do noting
	 */
	public void decode() {
		// do nothing
	} // decode

	/**
	 * Creates an exact copy of a Binary object
	 * 
	 * @return An exact copy of the object.
	 **/
	public Variable deepCopy() {
		return new Binary(this);
	} // deepCopy

	/**
	 * Returns the length of the binary string.
	 * 
	 * @return The length
	 */
	public int getNumberOfBits() {
		return numberOfBits_;
	} // getNumberOfBits

	/**
	 * Returns the value of the ith bit.
	 * 
	 * @param bit
	 *            The bit to retrieve
	 * @return The ith bit
	 */
	public boolean getIth(int bit) {
		return bits_.get(bit);
	} // getNumberOfBits

	/**
	 * Sets the value of the ith bit.
	 * 
	 * @param bit
	 *            The bit to set
	 */
	public void setIth(int bit, boolean value) {
		bits_.set(bit, value);
	} // getNumberOfBits

	/**
	 * Obtain the hamming distance between two binary strings
	 * 
	 * @param other
	 *            The binary string to compare
	 * @return The hamming distance
	 */
	public int hammingDistance(Binary other) {
		int distance = 0;
		int i = 0;
		while (i < bits_.size()) {
			if (bits_.get(i) != other.bits_.get(i)) {
				distance++;
			}
			i++;
		}
		return distance;
	} // hammingDistance

	/**
	 *  
	 */
	public String toString() {
		String result;

		result = "";
		for (int i = 0; i < numberOfBits_; i++)
			if (bits_.get(i))
				result = result + "1";
			else
				result = result + "0";

		return result;
	} // toString
} // Binary
